home *** CD-ROM | disk | FTP | other *** search
/ PC go! 2017 October / PCgo 10-2017 CD-ROM Germany.iso / nw.pak / Unnamed File 000137.txt < prev    next >
Encoding:
Text File  |  2015-07-29  |  9.3 KB  |  310 lines

  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. // <include src="../../assert.js">
  6.  
  7. cr.exportPath('cr.ui');
  8.  
  9. /**
  10.  * Enum for type of hide. Delayed is used when called by clicking on a
  11.  * checkable menu item.
  12.  * @enum {number}
  13.  */
  14. cr.ui.HideType = {
  15.   INSTANT: 0,
  16.   DELAYED: 1
  17. };
  18.  
  19. cr.define('cr.ui', function() {
  20.   /** @const */
  21.   var Menu = cr.ui.Menu;
  22.  
  23.   /** @const */
  24.   var HideType = cr.ui.HideType;
  25.  
  26.   /** @const */
  27.   var positionPopupAroundElement = cr.ui.positionPopupAroundElement;
  28.  
  29.   /**
  30.    * Creates a new menu button element.
  31.    * @param {Object=} opt_propertyBag Optional properties.
  32.    * @constructor
  33.    * @extends {HTMLButtonElement}
  34.    * @implements {EventListener}
  35.    */
  36.   var MenuButton = cr.ui.define('button');
  37.  
  38.   MenuButton.prototype = {
  39.     __proto__: HTMLButtonElement.prototype,
  40.  
  41.     /**
  42.      * Initializes the menu button.
  43.      */
  44.     decorate: function() {
  45.       this.addEventListener('mousedown', this);
  46.       this.addEventListener('keydown', this);
  47.  
  48.       // Adding the 'custom-appearance' class prevents widgets.css from changing
  49.       // the appearance of this element.
  50.       this.classList.add('custom-appearance');
  51.       this.classList.add('menu-button');  // For styles in menu_button.css.
  52.  
  53.       var menu;
  54.       if ((menu = this.getAttribute('menu')))
  55.         this.menu = menu;
  56.  
  57.       // An event tracker for events we only connect to while the menu is
  58.       // displayed.
  59.       this.showingEvents_ = new EventTracker();
  60.  
  61.       this.anchorType = cr.ui.AnchorType.BELOW;
  62.       this.invertLeftRight = false;
  63.     },
  64.  
  65.     /**
  66.      * The menu associated with the menu button.
  67.      * @type {cr.ui.Menu}
  68.      */
  69.     get menu() {
  70.       return this.menu_;
  71.     },
  72.     set menu(menu) {
  73.       if (typeof menu == 'string' && menu[0] == '#') {
  74.         menu = assert(this.ownerDocument.getElementById(menu.slice(1)));
  75.         cr.ui.decorate(menu, Menu);
  76.       }
  77.  
  78.       this.menu_ = menu;
  79.       if (menu) {
  80.         if (menu.id)
  81.           this.setAttribute('menu', '#' + menu.id);
  82.       }
  83.     },
  84.  
  85.     /**
  86.      * Whether to show the menu on press of the Up or Down arrow keys.
  87.      */
  88.     respondToArrowKeys: true,
  89.  
  90.     /**
  91.      * Handles event callbacks.
  92.      * @param {Event} e The event object.
  93.      */
  94.     handleEvent: function(e) {
  95.       if (!this.menu)
  96.         return;
  97.  
  98.       switch (e.type) {
  99.         case 'mousedown':
  100.           if (e.currentTarget == this.ownerDocument) {
  101.             if (e.target instanceof Node && !this.contains(e.target) &&
  102.                 !this.menu.contains(e.target)) {
  103.               this.hideMenu();
  104.             } else {
  105.               e.preventDefault();
  106.             }
  107.           } else {
  108.             if (this.isMenuShown()) {
  109.               this.hideMenu();
  110.             } else if (e.button == 0) {  // Only show the menu when using left
  111.                                          // mouse button.
  112.               this.showMenu(false);
  113.  
  114.               // Prevent the button from stealing focus on mousedown.
  115.               e.preventDefault();
  116.             }
  117.           }
  118.  
  119.           // Hide the focus ring on mouse click.
  120.           this.classList.add('using-mouse');
  121.           break;
  122.         case 'keydown':
  123.           this.handleKeyDown(e);
  124.           // If the menu is visible we let it handle all the keyboard events.
  125.           if (this.isMenuShown() && e.currentTarget == this.ownerDocument) {
  126.             if (this.menu.handleKeyDown(e)) {
  127.               e.preventDefault();
  128.               e.stopPropagation();
  129.             }
  130.           }
  131.  
  132.           // Show the focus ring on keypress.
  133.           this.classList.remove('using-mouse');
  134.           break;
  135.         case 'focus':
  136.           if (e.target instanceof Node && !this.contains(e.target) &&
  137.               !this.menu.contains(e.target)) {
  138.             this.hideMenu();
  139.             // Show the focus ring on focus - if it's come from a mouse event,
  140.             // the focus ring will be hidden in the mousedown event handler,
  141.             // executed after this.
  142.             this.classList.remove('using-mouse');
  143.           }
  144.           break;
  145.         case 'activate':
  146.           var hideDelayed = e.target instanceof cr.ui.MenuItem &&
  147.               e.target.checkable;
  148.           this.hideMenu(hideDelayed ? HideType.DELAYED : HideType.INSTANT);
  149.           break;
  150.         case 'scroll':
  151.           if (!(e.target == this.menu || this.menu.contains(e.target)))
  152.             this.hideMenu();
  153.           break;
  154.         case 'popstate':
  155.         case 'resize':
  156.           this.hideMenu();
  157.           break;
  158.       }
  159.     },
  160.  
  161.     /**
  162.      * Shows the menu.
  163.      * @param {boolean} shouldSetFocus Whether to set focus on the
  164.      *     selected menu item.
  165.      */
  166.     showMenu: function(shouldSetFocus) {
  167.       this.hideMenu();
  168.  
  169.       this.menu.updateCommands(this);
  170.  
  171.       var event = document.createEvent('UIEvents');
  172.       event.initUIEvent('menushow', true, true, window, null);
  173.  
  174.       if (!this.dispatchEvent(event))
  175.         return;
  176.  
  177.       this.menu.hidden = false;
  178.  
  179.       this.setAttribute('menu-shown', '');
  180.  
  181.       // When the menu is shown we steal all keyboard events.
  182.       var doc = this.ownerDocument;
  183.       var win = doc.defaultView;
  184.       this.showingEvents_.add(doc, 'keydown', this, true);
  185.       this.showingEvents_.add(doc, 'mousedown', this, true);
  186.       this.showingEvents_.add(doc, 'focus', this, true);
  187.       this.showingEvents_.add(doc, 'scroll', this, true);
  188.       this.showingEvents_.add(win, 'popstate', this);
  189.       this.showingEvents_.add(win, 'resize', this);
  190.       this.showingEvents_.add(this.menu, 'activate', this);
  191.       this.positionMenu_();
  192.  
  193.       if (shouldSetFocus)
  194.         this.menu.focusSelectedItem();
  195.     },
  196.  
  197.     /**
  198.      * Hides the menu. If your menu can go out of scope, make sure to call this
  199.      * first.
  200.      * @param {cr.ui.HideType=} opt_hideType Type of hide.
  201.      *     default: cr.ui.HideType.INSTANT.
  202.      */
  203.     hideMenu: function(opt_hideType) {
  204.       if (!this.isMenuShown())
  205.         return;
  206.  
  207.       this.removeAttribute('menu-shown');
  208.       if (opt_hideType == HideType.DELAYED)
  209.         this.menu.classList.add('hide-delayed');
  210.       else
  211.         this.menu.classList.remove('hide-delayed');
  212.       this.menu.hidden = true;
  213.  
  214.       this.showingEvents_.removeAll();
  215.       this.focus();
  216.     },
  217.  
  218.     /**
  219.      * Whether the menu is shown.
  220.      */
  221.     isMenuShown: function() {
  222.       return this.hasAttribute('menu-shown');
  223.     },
  224.  
  225.     /**
  226.      * Positions the menu below the menu button. At this point we do not use any
  227.      * advanced positioning logic to ensure the menu fits in the viewport.
  228.      * @private
  229.      */
  230.     positionMenu_: function() {
  231.       positionPopupAroundElement(this, this.menu, this.anchorType,
  232.                                  this.invertLeftRight);
  233.     },
  234.  
  235.     /**
  236.      * Handles the keydown event for the menu button.
  237.      */
  238.     handleKeyDown: function(e) {
  239.       switch (e.keyIdentifier) {
  240.         case 'Down':
  241.         case 'Up':
  242.           if (!this.respondToArrowKeys)
  243.             break;
  244.         case 'Enter':
  245.         case 'U+0020': // Space
  246.           if (!this.isMenuShown())
  247.             this.showMenu(true);
  248.           e.preventDefault();
  249.           break;
  250.         case 'Esc':
  251.         case 'U+001B': // Maybe this is remote desktop playing a prank?
  252.         case 'U+0009': // Tab
  253.           this.hideMenu();
  254.           break;
  255.       }
  256.     }
  257.   };
  258.  
  259.   /**
  260.    * Helper for styling a menu button with a drop-down arrow indicator.
  261.    * Creates a new 2D canvas context and draws a downward-facing arrow into it.
  262.    * @param {string} canvasName The name of the canvas. The canvas can be
  263.    *     addressed from CSS using -webkit-canvas(<canvasName>).
  264.    * @param {number} width The width of the canvas and the arrow.
  265.    * @param {number} height The height of the canvas and the arrow.
  266.    * @param {string} colorSpec The CSS color to use when drawing the arrow.
  267.    */
  268.   function createDropDownArrowCanvas(canvasName, width, height, colorSpec) {
  269.     var ctx = document.getCSSCanvasContext('2d', canvasName, width, height);
  270.     ctx.fillStyle = ctx.strokeStyle = colorSpec;
  271.     ctx.beginPath();
  272.     ctx.moveTo(0, 0);
  273.     ctx.lineTo(width, 0);
  274.     ctx.lineTo(height, height);
  275.     ctx.closePath();
  276.     ctx.fill();
  277.     ctx.stroke();
  278.   };
  279.  
  280.   /** @const */ var ARROW_WIDTH = 6;
  281.   /** @const */ var ARROW_HEIGHT = 3;
  282.  
  283.   /**
  284.    * Create the images used to style drop-down-style MenuButtons.
  285.    * This should be called before creating any MenuButtons that will have the
  286.    * CSS class 'drop-down'. If no colors are specified, defaults will be used.
  287.    * @param {string=} opt_normalColor CSS color for the default button state.
  288.    * @param {string=} opt_hoverColor CSS color for the hover button state.
  289.    * @param {string=} opt_activeColor CSS color for the active button state.
  290.    */
  291.   MenuButton.createDropDownArrows = function(
  292.       opt_normalColor, opt_hoverColor, opt_activeColor) {
  293.     opt_normalColor = opt_normalColor || 'rgb(192, 195, 198)';
  294.     opt_hoverColor = opt_hoverColor || 'rgb(48, 57, 66)';
  295.     opt_activeColor = opt_activeColor || 'white';
  296.  
  297.     createDropDownArrowCanvas(
  298.         'drop-down-arrow', ARROW_WIDTH, ARROW_HEIGHT, opt_normalColor);
  299.     createDropDownArrowCanvas(
  300.         'drop-down-arrow-hover', ARROW_WIDTH, ARROW_HEIGHT, opt_hoverColor);
  301.     createDropDownArrowCanvas(
  302.         'drop-down-arrow-active', ARROW_WIDTH, ARROW_HEIGHT, opt_activeColor);
  303.   };
  304.  
  305.   // Export
  306.   return {
  307.     MenuButton: MenuButton,
  308.   };
  309. });
  310.